07-10 链接器及汇编语言混合编程
07 揭开链接器的面纱(上)
问题:源文件被编译后生成目标文件,这些目标文件如何生成最终的可执行程序?
链接器的意义:链接器的主要作用是把各个模块之间相互引用的部分处理好,使得各个模块之间能够正确的衔接。
目标文件的秘密
- 各个段没有具体的起始地址,只有段大小信息
- 各个标识符没有实际地址,只有段中的相对地址
- 段和标识符的实际地址需要链接器具体确定
链接器的工作内容:将目标文件和库文件整合为最终的可执行程序。
- 合并各个目标文件中的段(
.text
,.data
,.bss
) - 确定各个段和段中标识符的最终地址(重定位)
问题:main()
函数是第一个被调用执行的函数吗?
默认情况下(gcc
)
- 程序加载后,
_start()
是第一个被调用执行的函数_ _start()
函数准备好参数后立即调用__libc_start_main()
函数__libc_start_main()
初始化运行环境后调用main()
函数执行
_start()
函数的入口地址就是代码段(.text
)的起始地址!
__libc_start_main()
函数的作用
- 调用
__libc_csu_init()
函数(完成必要的初始化操作) - 启动程序的第一个线程(主线程),
main()
为线程入口 - 注册
__libc_csu_fini()
函数(程序运行终止时被调用)
程序的启动过程
自定义程序入口函数
-
gcc
提供-e
选项用于在链接时指定入口函数 -
自定义入口函数时必须使用
-nostartfiles
选项进行链接#include <stdio.h>
#include <stdlib.h>
int program() { //Entry Function
printf("Hello World!");
exit(0);
}
// gcc main.c -e program -nostartfiles
思考:链接选项 -nostartfiles
的意义是什么?链接器根据什么原则完成具体的工作?
重要链接选项
-nostartfiles
Do not use the standard system startup fles when linking. The standard system libraries are used normally, unless ‘-nostdlib’ or ‘-nodefaultlibs’ is used.-nodefaultlibs
Do not use the standard system libraries when linking. Only the libraries you specify are passed to the linker, and options specifying linkage of the system libraries, such as ‘-static-libgcc’ or ‘-shared-libgcc’, are ignored. The standard startup fles are used normally, unless ‘-nostartfiles’ is used. The compiler may generate calls to memcmp, memset, memcpy and memmove. These entries are usually resolved by entries in libc. These entry points should be supplied through some other mechanism when this option is specifed.-nostdlib
Do not use the standard system startup fles or libraries when linking. No startup fles and only the libraries you specify are passed to the linker, and options specifying linkage of the system libraries, such as ‘-static-libgcc’ or ‘-shared-libgcc’, are ignored. The compiler may generate calls to memcmp, memset, memcpy and memmove. These entries are usually resolved by entries in libc. These entry points should be supplied through some other mechanism when this option is specifed.
08 揭开链接器的面纱(中)
思考:链接器根据什么原则完成具体的工作?
链接脚本的概念和意义:链接脚本用于描述链接器处理目标文件和库文件的方式。
- 合并各个目标文件中的段
- 重定位各个段的起始地址
- 重定位各个符号的最终地址
链接脚本的本质
链接脚本初探(Round 1)
SECTIONS //关键字,描述各个段在内存中的布局
{
.text 0x2000000: //代码段起始地址
{
*(.text) //所有目标文件中的代码段合并进入可执行程序
}
. = 0x8000000 //设置当前地址
S = .; //设置标识符S的存储地址
.data 0x3000000:
{
*(.data)
}
.bss:
{
*(.bss)
}
}
注意事项
- 各个段的链接地址必须符合具体平台的规范
- 链接脚本中能够直接定义标识符并指定存储地址
- 链接脚本中能够指定源代码中标识符的存储地址
在Linux中,进程代码段(.text)的合法起始地址为[0x08048000,0x08049000]